home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 076-100 / disk_093 / dme / keyboard.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  13KB  |  568 lines

  1.  
  2. /*
  3.  *  KEYBOARD.C
  4.  *
  5.  *    (C)Copyright 1987 by Matthew Dillon
  6.  *
  7.  *  Handle keyboard related stuff such as keyboard mappings.  Every time
  8.  *  a key is pressed, KEYCTL() is called with the code.  KEYCTL() remembers
  9.  *  which qualifier keys are currently held down, and when a non-qualifier
  10.  *  key is pressed finds the hash entry for the key.  If no hash entry
  11.  *  exists (e.g. you type a normal 'a') the default keymap is used.
  12.  */
  13.  
  14. #include "defs.h"
  15.  
  16. typedef struct IOStdReq CIO;
  17.  
  18. #define QUAL_SHIFT   0x01
  19. #define QUAL_CTRL    0x02
  20. #define QUAL_AMIGA   0x04
  21. #define QUAL_ALT     0x08
  22. #define QUAL_LMB     0x10
  23. #define QUAL_MMB     0x20
  24. #define QUAL_RMB     0x40
  25.  
  26. #define XBITSET(array,bit)   (array[(bit)>>3] |= 1<<((bit)&7))
  27. #define XBITTEST(array,bit)  (array[(bit)>>3] & 1<<((bit)&7))
  28.  
  29.  
  30. #define HASHSIZE  64
  31.  
  32. typedef struct _HASH {
  33.     struct _HASH *next;     /* next hash   */
  34.     u_char code;        /* keycode       */
  35.     u_char mask;        /* qual. mask  */
  36.     u_char qual;        /* qual. comp  */
  37.     u_char stat;        /* string static? */
  38.     char *str;            /* command string */
  39. } HASH;
  40.  
  41. HASH *Hash[HASHSIZE];
  42.  
  43. static u_char isascii[0x80/8];    /* is printable ascii    */
  44. static u_char isalpha[0x80/8];    /* is alpha a-z/A-Z    */
  45. static u_char ctoa[0x80];    /* cvt to character        */
  46. static u_char cstoa[0x80];    /* cvt to shifted chacter   */
  47.  
  48. dealloc_hash()
  49. {
  50.     register HASH *hash, *hnext = NULL;
  51.     register short i;
  52.  
  53.     for (i = 0; i < HASHSIZE; ++i) {
  54.     for (hash = Hash[i]; hash; hash = hnext) {
  55.         hnext = hash->next;
  56.         if (!hash->stat)
  57.         FreeMem(hash->str, strlen(hash->str)+1);
  58.         FreeMem(hash, sizeof(HASH));
  59.     }
  60.     Hash[i] = NULL;
  61.     }
  62. }
  63.  
  64. resethash()
  65. {
  66.     register short i;
  67.  
  68.     static struct {
  69.     char *from, *to;
  70.     } defmap[] = {
  71.     "esc",      "esc",
  72.     "return",   "return insline up firstnb down",
  73.     "enter",    "return",
  74.     "up",       "up",
  75.     "down",     "down",
  76.     "right",    "right",
  77.     "left",     "left",
  78.     "bs",       "bs",
  79.     "del",      "del",
  80.     "help",     "newwindow newfile s:DME.DOC escimm `find '",
  81.     "tab",      "tab",
  82.     "s-up",     "top",
  83.     "s-down",   "bottom",
  84.     "s-right",  "last",
  85.     "s-left",   "first",
  86.     "s-tab",    "backtab",
  87.     "s-del",    "deline",
  88.     "s- ",      "` '",              /* shift space to space */
  89.     "c-l",      "wleft",
  90.     "c-r",      "wright",
  91.     "c-i",      "insertmode on",
  92.     "c-o",      "insertmode off",
  93.     "c-j",      "join",
  94.     "c-s",      "split first down",
  95.     "c-del",    "remeol",
  96.     "c-n",      "next",
  97.     "c-p",      "prev",
  98.     "c-/",      "escimm `find '",
  99.     "c-g",      "escimm `goto '",
  100.     "c-up",     "pageup",
  101.     "c-down",   "pagedown",
  102.     "c-q",      "quit",
  103.     "c-f",      "reformat",
  104.     "c-w",      "wordwrap toggle",
  105.     "f1",       "escimm `insfile '",
  106.     "f2",       "escimm `newfile '",
  107.     "f3",       "escimm `newwindow newfile '",
  108.     "f7",       "escimm `bsave '",
  109.     "f8",       "saveold escimm `newfile '",
  110.     "f9",       "saveold",
  111.     "f10",      "saveold quit",
  112.     "c-b",      "block",
  113.     "c-u",      "unblock",
  114.     "a-d",      "bdelete",
  115.     "a-c",      "bcopy",
  116.     "a-m",      "bmove",
  117.     "a-s",      "bsource",
  118.     "a-S",      "unblock block block bsource",
  119.     "L-lmb",    "tomouse",      /*  left button                 */
  120.     "L-mmo",    "tomouse",      /*  mouse move w/left held down */
  121.     "R-rmb",    "iconify",      /*  right button                */
  122.     NULL, NULL
  123.     };
  124.  
  125.     dealloc_hash();
  126.     loaddefaultkeymap();
  127.     for (i = 0; defmap[i].from; ++i) {
  128.     u_char code, qual;
  129.     if (get_codequal(defmap[i].from, &code, &qual))
  130.         addhash(code, 1, 0xFF, qual, defmap[i].to);
  131.     }
  132. }
  133.  
  134. /*
  135.  *  Go through keycodes $00 to $4F and load the ctoa[], cstoa[], and
  136.  *  isalpha[] char tables from the default console keymap.
  137.  */
  138.  
  139. loaddefaultkeymap()
  140. {
  141.     CIO cio;
  142.     struct KeyMap km;
  143.  
  144.     /*
  145.      * Note: -1 specification for unit # means that we are not openning
  146.      * a real console.    We can only execute a CD_ASKDEFAULTKEYMAP through
  147.      * it.
  148.      */
  149.  
  150.     if (!OpenDevice("console.device", -1, &cio, 0)) {
  151.     cio.io_Command = CD_ASKDEFAULTKEYMAP;
  152.     cio.io_Data = (APTR)&km;
  153.     cio.io_Length = sizeof(km);
  154.     DoIO(&cio);
  155.     loadhilo(km.km_LoKeyMapTypes, km.km_LoKeyMap, km.km_LoCapsable, 0, 0x40, 0x00);
  156.     loadhilo(km.km_HiKeyMapTypes, km.km_HiKeyMap, km.km_HiCapsable, 0, 0x10, 0x40);
  157.     CloseDevice(&cio);
  158.     } else {
  159.     if (Output())
  160.         puts ("Unable to get console keymap");
  161.     }
  162. }
  163.  
  164.  
  165. /*
  166.  *  Decode plain and shifted keys only.  Ignore strings larger than
  167.  *  a single character (thus things like the cursor keys do not get
  168.  *  mapped)
  169.  */
  170.  
  171. loadhilo(types, map, caps, is, ie, ia)
  172. u_char *types;
  173. u_char *caps;
  174. long *map;
  175. {
  176.     register long n;
  177.     register int idx;
  178.     register u_char *ptr;
  179.     u_char c;
  180.  
  181.     for (; is < ie; ++is) {
  182.     n = map[is];
  183.     if (n && (types[is] & 0x60)) {        /*    STRING 0x40 or BUG 0x20 */
  184.         ptr = (u_char *)n;
  185.         n = 0;
  186.         if (ptr[0] == 0)
  187.         n = ptr[1];
  188.         if (ptr[0] == 1)
  189.         n = ptr[ptr[1]];
  190.         if (types[is] & KCF_SHIFT) {
  191.         if (ptr[2] == 0)
  192.             n |= ptr[3] << 8;
  193.         if (ptr[2] == 1)
  194.             n |= ptr[ptr[3]] << 8;
  195.         }
  196.     }
  197.     idx = is + ia;
  198.     c = n;
  199.     ctoa[idx] = c;
  200.     cstoa[idx] = (n>>8) & 0xFF;
  201.     if (caps[is>>3] & (1 << (is&7)))
  202.         XBITSET(isalpha,idx);
  203.     if (c >= 32 && c != 0x7F && ctoa[idx])
  204.         XBITSET(isascii,idx);
  205.     }
  206. }
  207.  
  208.  
  209. returnoveride(n)
  210. {
  211.     HASH *hash;
  212.     static u_char *str;
  213.     static int stat;
  214.  
  215.     for (hash = Hash[0x44 % HASHSIZE]; hash; hash = hash->next) {
  216.     if (hash->code == 0x44 && hash->qual == 0) {
  217.         if (n) {
  218.         str = (u_char *)hash->str;
  219.         stat= hash->stat;
  220.         hash->str = "return";
  221.         hash->stat = 1;
  222.         } else {
  223.         if (str == NULL) {
  224.             remhash(0x44, -1, 0);
  225.         } else {
  226.             hash->str = (char *)str;
  227.             hash->stat= stat;
  228.         }
  229.         }
  230.         return(0);
  231.     }
  232.     }
  233.     if (n) {
  234.     addhash(0x44, 1, 0xFF, 0, "return");
  235.     str = NULL;
  236.     }
  237. }
  238.  
  239.  
  240.  
  241. addhash(code, stat, mask, qual, str)
  242. u_char code, stat, mask, qual;
  243. u_char *str;
  244. {
  245.     register HASH **p, *hash;
  246.  
  247.     hash = *(p = &Hash[code % HASHSIZE]);
  248.     while (hash) {
  249.     if (hash->code == code && hash->qual == qual && hash->mask == mask) {
  250.         if (!hash->stat)
  251.         FreeMem(hash->str, strlen(hash->str)+1);
  252.         goto newstr;
  253.     }
  254.     hash = *(p = &hash->next);
  255.     }
  256.     *p = hash = (HASH *)AllocMem(sizeof(HASH), 0);
  257.     hash->next = NULL;
  258. newstr:
  259.     hash->code = code;
  260.     hash->stat = stat;
  261.     hash->mask = mask;
  262.     hash->qual = qual;
  263.     hash->str = (char *)str;
  264.     if (!stat)            /* if not static */
  265.     hash->str = (char *)strcpy(AllocMem(strlen(str)+1, 0), str);
  266. }
  267.  
  268.  
  269. remhash(code, mask, qual)
  270. u_char code, mask, qual;
  271. {
  272.     register HASH *hash, **p;
  273.  
  274.     hash = *(p = &Hash[code % HASHSIZE]);
  275.     while (hash) {
  276.     if (hash->code == code && hash->qual == qual && hash->mask == mask) {
  277.         if (!hash->stat)
  278.         FreeMem(hash->str, strlen(hash->str)+1);
  279.         *p = hash->next;
  280.         FreeMem(hash, sizeof(HASH));
  281.         return(1);
  282.     }
  283.     hash = *(p = &hash->next);
  284.     }
  285.     return(0);
  286. }
  287.  
  288.  
  289. keyctl(code, qual)
  290. register USHORT qual;
  291. {
  292.     register u_char c, c2;
  293.     register HASH *hash;
  294.  
  295.     code &= 0xFF;
  296.  
  297.     if ((code & 0x78) == 0x60)        /*    forget qualifier keys    */
  298.     return(0);
  299.     if (code & 0x80)            /*    forget upstrokes    */
  300.     return(0);
  301.  
  302.     c2 = 0;
  303.     if (qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  304.     c2 |= QUAL_SHIFT;
  305.     if (qual & (IEQUALIFIER_CONTROL))
  306.     c2 |= QUAL_CTRL;
  307.     if (qual & (IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND))
  308.     c2 |= QUAL_AMIGA;
  309.     if (qual & (IEQUALIFIER_LALT|IEQUALIFIER_RALT))
  310.     c2 |= QUAL_ALT;
  311.     if ((qual & IEQUALIFIER_CAPSLOCK) && (code <= 0x37) && XBITTEST(isalpha,code))
  312.     c2 |= QUAL_SHIFT;
  313.     if (qual & IEQUALIFIER_LEFTBUTTON)
  314.     c2 |= QUAL_LMB;
  315.     if (qual & IEQUALIFIER_MIDBUTTON)
  316.     c2 |= QUAL_MMB;
  317.     if (qual & (IEQUALIFIER_RBUTTON))
  318.     c2 |= QUAL_RMB;
  319.     for (hash = Hash[code % HASHSIZE]; hash; hash = hash->next) {
  320.     if (hash->code == code) {
  321.         if ((c2 & hash->mask) == hash->qual)
  322.         break;
  323.     }
  324.     }
  325.  
  326.     /*
  327.      *    Use hash entry only if not in command line mode, or if the
  328.      *    entry does not correspond to an alpha key.
  329.      */
  330.  
  331.     if (hash) {
  332.     char buf[256];
  333.     /*printf ("c2 %lx BIT: %lx\n", c2, XBITTEST(isascii,code));*/
  334.     if (c2 || !ComLineMode || !XBITTEST(isascii,code)) {
  335.         strcpy(buf, hash->str);
  336.         do_command(buf);
  337.         return(0);
  338.     }
  339.     }
  340.  
  341.     if (code < 0x50) {
  342.     c = (c2 & QUAL_SHIFT) ? cstoa[code] : ctoa[code];
  343.     if (c2 & QUAL_CTRL)
  344.         c &= 0x1F;
  345.     if (c && (c2 & QUAL_ALT))
  346.         c |= 0x80;
  347.     if (c && (c2 & QUAL_AMIGA))
  348.         c |= 0xC0;
  349.     if (c) {
  350.         u_char buf[3];
  351.         buf[0] = '\'';
  352.         buf[1] = c;
  353.         buf[2] = 0;
  354.         do_command(buf);
  355.     }
  356.     }
  357. }
  358.  
  359. #define LN(a,b,c,d)  ((a<<24)|(b<<16)|(c<<8)|d)
  360.  
  361. long lname[] = {
  362.     LN('e','s','c',0x45), LN('f','1', 0 ,0x50), LN('f','2', 0 ,0x51),
  363.     LN('f','3', 0 ,0x52), LN('f','4', 0 ,0x53), LN('f','5', 0 ,0x54),
  364.     LN('f','6', 0 ,0x55), LN('f','7', 0 ,0x56), LN('f','8', 0 ,0x57),
  365.     LN('f','9', 0 ,0x58), LN('f','1','0',0x59), LN('d','e','l',0x46),
  366.     LN('b','a','c',0x41), LN('b','s', 0 ,0x41), LN('t','a','b',0x42),
  367.     LN('h','e','l',0x5F), LN('r','e','t',0x44), LN('u','p', 0 ,0x4C),
  368.     LN('d','o','w',0x4D), LN('r','i','g',0x4E), LN('l','e','f',0x4F),
  369.     LN('e','n','t',0x43), LN('n','k','-',0x4A), LN('n','k','.',0x3C),
  370.     LN('n','k','0',0x0F),
  371.     LN('n','k','1',0x1D), LN('n','k','2',0x1E), LN('n','k','3',0x1F),
  372.     LN('n','k','4',0x2D), LN('n','k','5',0x2E), LN('n','k','6',0x2F),
  373.     LN('n','k','7',0x3D), LN('n','k','8',0x3E), LN('n','k','9',0x3F),
  374.     LN('l','m','b',0x68), LN('m','m','b',0x6A), LN('r','m','b',0x69),
  375.     LN('m','m','o',QMOVE),
  376.     0
  377. };
  378.  
  379.  
  380. char *
  381. keyspectomacro(str)
  382. char *str;
  383. {
  384.     HASH *hash;
  385.     u_char code, qual;
  386.  
  387.     if (get_codequal(str, &code, &qual)) {
  388.     for (hash = Hash[code % HASHSIZE]; hash; hash = hash->next) {
  389.         if (hash->code == code) {
  390.         if (hash->qual == (qual & hash->mask))
  391.             return(hash->str);
  392.         }
  393.     }
  394.     }
  395.     title ("Bad command or unmapped key");
  396.     return(NULL);
  397. }
  398.  
  399.  
  400. get_codequal(str, pcode, pqual)
  401. u_char *pcode, *pqual;
  402. u_char *str;
  403. {
  404.     u_char qual;
  405.     register short i;
  406.  
  407.     qual = 0;
  408.     if (strlen(str) > 1) {
  409.     for (; *str && *str != '-'; ++str) {
  410.         if (*str == 's')
  411.         qual |= QUAL_SHIFT;
  412.         if (*str == 'c')
  413.         qual |= QUAL_CTRL;
  414.         if (*str == 'a')
  415.         qual |= QUAL_ALT;
  416.         if (*str == 'A')
  417.         qual |= QUAL_AMIGA;
  418.         if (*str == 'L')
  419.         qual |= QUAL_LMB;
  420.         if (*str == 'M')
  421.         qual |= QUAL_MMB;
  422.         if (*str == 'R')
  423.         qual |= QUAL_RMB;
  424.         if (!qual)
  425.         goto notqual;
  426.     }
  427.     if (*str)
  428.         ++str;
  429.     }
  430. notqual:
  431.     *pqual = qual;
  432.     if (strlen(str) != 1) {          /* long name   */
  433.     register short shift = 24;
  434.     register long mult = 0;
  435.  
  436.     while (*str && shift >= 8) {
  437.         if (*str >= 'A' && *str <= 'Z')
  438.         *str = *str - 'A' + 'a';
  439.         mult |= *str << shift;
  440.         shift -= 8;
  441.         ++str;
  442.     }
  443.     for (i = 0; lname[i]; ++i) {
  444.         if (mult == (lname[i] & 0xFFFFFF00)) {
  445.         *pcode = lname[i] & 0x7F;
  446.         return(1);
  447.         }
  448.     }
  449.     } else {                 /* short name  */
  450.     for (i = 0; i < sizeof(ctoa); ++i) {
  451.         if (*str == ctoa[i]) {
  452.         *pcode = i;
  453.         return(1);
  454.         }
  455.     }
  456.     for (i = 0; i < sizeof(cstoa); ++i) {
  457.         if (*str == cstoa[i]) {
  458.         *pcode = i;
  459.         *pqual |= QUAL_SHIFT;
  460.         return(1);
  461.         }
  462.     }
  463.     }
  464.     return(0);
  465. }
  466.  
  467. u_char *
  468. cqtoa(code, qual)
  469. {
  470.     static u_char buf[32];
  471.     register u_char *ptr = buf;
  472.     register int i;
  473.  
  474.     if (qual & QUAL_SHIFT)
  475.     *ptr++ = 's';
  476.     if (qual & QUAL_CTRL)
  477.     *ptr++ = 'c';
  478.     if (qual & QUAL_ALT)
  479.     *ptr++ = 'a';
  480.     if (qual & QUAL_AMIGA)
  481.     *ptr++ = 'A';
  482.     if (qual & QUAL_LMB)
  483.     *ptr++ = 'L';
  484.     if (qual & QUAL_MMB)
  485.     *ptr++ = 'M';
  486.     if (qual & QUAL_RMB)
  487.     *ptr++ = 'R';
  488.     if (qual)
  489.     *ptr++ = '-';
  490.     for (i = 0; i < sizeof(lname)/sizeof(lname[0]); ++i) {
  491.     if ((lname[i]&0xFF) == code) {
  492.         *ptr++ = (lname[i]>>24);
  493.         *ptr++ = (lname[i]>>16);
  494.         *ptr++ = (lname[i]>>8);
  495.         break;
  496.     }
  497.     }
  498.     if (i == sizeof(lname)/sizeof(lname[0]))
  499.     *ptr++ = ctoa[code];
  500.     *ptr++ = 0;
  501.     return(buf);
  502. }
  503.  
  504.  
  505. do_map()
  506. {
  507.     u_char code, qual;
  508.  
  509.     if (get_codequal(av[1], &code, &qual)) {
  510.     addhash(code, 0, 0xFF, qual, av[2]);
  511.     } else {
  512.     title("Unknown Key");
  513.     }
  514. }
  515.  
  516. do_unmap()      /* key   */
  517. {
  518.     u_char code, qual;
  519.  
  520.     if (get_codequal(av[1], &code, &qual)) {
  521.     remhash(code, -1, qual);
  522.     } else {
  523.     title("Unknown Command");
  524.     }
  525. }
  526.  
  527. do_clearmap()
  528. {
  529.     resethash();
  530. }
  531.  
  532. /*
  533.  * SAVEMAP  file
  534.  * SAVESMAP file
  535.  */
  536.  
  537. do_savemap()
  538. {
  539.     char sysalso;
  540.     char err = 0;
  541.     u_char buf[256];
  542.     long fi;
  543.     register int i;
  544.     register HASH *hash;
  545.  
  546.     fi = xopen(av[1], "w", 512);
  547.     if (fi) {
  548.     sysalso = av[0][4] == 's';
  549.     for (i = 0; i < HASHSIZE; ++i) {
  550.         for (hash = Hash[i]; hash; hash = hash->next) {
  551.         if (hash->stat == 0 || sysalso) {
  552.             sprintf(buf, "map `%s' `%s'", cqtoa(hash->code, hash->qual), hash->str);
  553.             xputs(fi, buf);
  554.         }
  555.         }
  556.     }
  557.     xclose(fi);
  558.     if (err)
  559.         title ("Unable to Write");
  560.     else
  561.         title ("OK");
  562.     } else {
  563.     title("Unable to open file");
  564.     }
  565. }
  566.  
  567.  
  568.